﻿Imports System.Runtime.Serialization
Imports System.Data.Common
Imports System.Data.SqlClient
Imports System.Text
Imports Microsoft.SqlServer.Management.Smo
Imports Microsoft.SqlServer.Management.Common

''' <summary>
''' A Script
''' </summary>
''' <remarks>The execution of the script needs to be decoupled from the storage of the script.</remarks>
<DataContract(Namespace:=Constants.DataContractNamespace)> _
Public Class Script
    Inherits ItemBase

    Private _output As StringBuilder
    Private _name As String
    Private _commandText As String
    Private _fileName As String
    Private _scriptType As ScriptTypes
    Private _directory As String
    Private _filter As String

#Region " Properties"
    ''' <summary>
    ''' Gets or sets the name of the script
    ''' </summary>
    ''' <value></value>
    ''' <remarks></remarks>
    <DataMember()> _
    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value

            MarkDirty("Name")
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the CommandText of the script
    ''' </summary>
    ''' <value></value>
    ''' <remarks></remarks>
    <DataMember()> _
    Public Property CommandText() As String
        Get
            Return _commandText
        End Get
        Set(ByVal value As String)
            _commandText = value

            MarkDirty("CommandText")
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the filename of the script
    ''' </summary>
    ''' <value></value>
    ''' <remarks></remarks>
    <DataMember()> _
    Public Property FileName() As String
        Get
            Return _fileName
        End Get
        Set(ByVal value As String)
            _fileName = value

            MarkDirty("FileName")
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the ScriptType of the script
    ''' </summary>
    ''' <value></value>
    ''' <remarks></remarks>
    <DataMember()> _
    Public Property ScriptType() As ScriptTypes
        Get
            Return _scriptType
        End Get
        Set(ByVal value As ScriptTypes)
            _scriptType = value

            MarkDirty("ScriptType")
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the root directory to be used when the script type is directory
    ''' </summary>
    ''' <value></value>
    ''' <remarks></remarks>
    <DataMember()> _
    Public Property Directory() As String
        Get
            Return _directory
        End Get
        Set(ByVal value As String)
            _directory = value

            MarkDirty("Directory")
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the filter to be used when the ScriptType is Directory
    ''' </summary>
    ''' <value></value>
    ''' <remarks></remarks>
    <DataMember()> _
    Public Property Filter() As String
        Get
            Return _filter
        End Get
        Set(ByVal value As String)
            _filter = value

            MarkDirty("Filter")
        End Set
    End Property
#End Region

#Region " Methods"
    ''' <summary>
    ''' Gets the script items for this script
    ''' </summary>
    ''' <param name="baseDirectory"></param>
    ''' <remarks>
    ''' A Script can actually resolve to more than one script item in the case of a script
    ''' of type Directory.  In that case, all of the scripts in that directory (and child directories) are executed.
    ''' </remarks>
    ''' <returns>The list of script items for this script.</returns>
    Friend Function GetScriptItems(ByVal baseDirectory As String) As ScriptItems

        Dim scriptItems As New ScriptItems

        Select Case Me.ScriptType
            Case ScriptTypes.CommandText

                'Add the item to the list
                scriptItems.Add(New ScriptItem(Me.Name, Me.CommandText))

            Case ScriptTypes.Directory

                Dim effectiveDirectory As String

                'Check to see if we have a baseDirectory to work with
                If String.IsNullOrEmpty(baseDirectory) Then

                    'Just use the directory specified by the script
                    effectiveDirectory = Me.Directory

                Else

                    'We have a base directory - combine the paths
                    effectiveDirectory = IO.Path.Combine(baseDirectory, Me.Directory)
                End If

                'Check to see if the user has provided file searches
                If String.IsNullOrEmpty(Me.Filter) Then

                    'Get the files
                    AddScriptItemsFromDirectory(effectiveDirectory, scriptItems)
                Else

                    'Get the filters (we're assuming that the list is separated by commas)
                    Dim searches() As String = Me.Filter.Split(","c)

                    'Let's examine each string
                    For Each search As String In searches

                        'Check to see if there is a search to work with
                        If Not String.IsNullOrEmpty(search) Then

                            'Trim the string
                            search = search.Trim()

                            'Check it again
                            If Not String.IsNullOrEmpty(search) Then

                                'Add the items
                                AddScriptItemsFromDirectory(effectiveDirectory, scriptItems, search)

                            End If
                        End If
                    Next
                End If

            Case ScriptTypes.ScriptName

                'Get the path of the file
                Dim path As String = IO.Path.Combine(baseDirectory, Me.FileName)

                'Read the text from the file
                Dim commandText As String = System.IO.File.ReadAllText(path)

                'Add the item to the list
                scriptItems.Add(New ScriptItem(Me.Name, commandText))

            Case Else
                Throw New InvalidOperationException(String.Format("Unable to get the script items for a script of type '{0}'.", Me.ScriptType))
        End Select

        Return scriptItems

    End Function

    ''' <summary>
    ''' Adds scripts from a directory to the list of script items
    ''' </summary>
    ''' <param name="directory"></param>
    ''' <param name="scriptItems"></param>
    ''' <remarks></remarks>
    Private Sub AddScriptItemsFromDirectory(ByVal directory As String, _
                                            ByVal scriptItems As ScriptItems, _
                                            Optional ByVal search As String = Nothing)

        'This is the list of files
        Dim files() As String


        'Check to see if we have a search string
        If String.IsNullOrEmpty(search) Then
            files = IO.Directory.GetFiles(directory)
        Else
            files = IO.Directory.GetFiles(directory, search, IO.SearchOption.AllDirectories)
        End If

        'Deal with each of the files
        For Each file As String In files

            'Get the command text
            Dim commandText As String = IO.File.ReadAllText(file)

            Dim displayName As String = String.Format("{0} - {1}", Me.Name, file)

            'Add the item
            scriptItems.Add(New ScriptItem(displayName, commandText))

        Next

    End Sub

#End Region

End Class
